package minijvm.engine;

import minijvm.method.Method;

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

/**
 * @author ChangLiang
 * @date 2020/4/28
 */
public class ExecutorEngine {

    /**
     * 执行引擎中 有一个函数栈帧 的 stack
     */
    private Stack<StackFrame> stack = new Stack<>();

    public void execute(Method mainMethod) {
        stack.push(StackFrame.create(mainMethod));
        while (!stack.isEmpty()) {
            StackFrame frame = stack.peek();
            ExecutionResult result = frame.execute();
            if (result.isExitCurrentFrame()) {
                stack.pop();
            } else if (result.isPauseAndRunNewFrame()) {
                Method m = result.getNextMethod();
                StackFrame stackFrame = StackFrame.create(m);
                // 给当前栈帧设置上一级栈帧
                stackFrame.setCallerFrame(frame);
                // 参数传递 将上一级栈帧中操作数栈 中的值 放到 新建栈帧的局部变量表中
                this.setupFunctionCallParams(frame,stackFrame);
                stack.push(stackFrame);
            }
        }
    }

    /**
     * 从上一个栈帧的操作数栈中弹出值 放到 下一个栈帧的局部变量表中 模拟参数传递
     * @param currentFrame
     * @param nextFrame
     */
    private void setupFunctionCallParams(StackFrame currentFrame, StackFrame nextFrame) {
        Method m = nextFrame.getMethod();
        List<String> paramList = m.getParameterList();
        // 需要传递this 所以要加1
        int paramNum = paramList.size() + 1;

        List<JavaObject> values = new ArrayList<>();
        // 数据结构知识：从栈顶取出栈顶的paramNum个元素
        // values: 29->andy->this
        while (paramNum > 0) {
            values.add(currentFrame.getOperandStack().pop());
            paramNum--;
        }
        // 数据结构知识：把一个列表倒序排列
        // params: this->andy->29
        List<JavaObject> params = new ArrayList<>();
        for (int i = values.size()-1; i >=0 ; i--) {
            params.add(values.get(i));
        }
        // 设置下一个函数栈帧的局部变量表
        nextFrame.setLocalVariableTable(params);

    }
}
